//
//	File: OyDirect3D9_VertexCache.h
//

#ifndef OYDIRECT3D9_VERTEXCACHE_H
#define OYDIRECT3D9_VERTEXCACHE_H

#include "../OyRenderer/OyRenderDevice.h"
#include "OyDirect3D9_MaterialSystem.h"
#include "DataStruct/OyDataStruct.h"
#include "../OyMath3D/OyMath3D.h"
#include <d3d9.h>

class OySkinManager;
class OyDirect3D9;
class OyD3D9VertexCache;


class OyD3D9StaticBuffer
{
public:
	UINT  nSBID;
	int   nStride;
	UINT  nSkinID;
	int   nNumVerts;
	int   nNumIndis;
	int   nNumTris;

	LPDIRECT3DVERTEXDECLARATION9			pDecl;
	LPDIRECT3DVERTEXBUFFER9					pVB;
	LPDIRECT3DINDEXBUFFER9					pIB;
	OyAABB									BoundingBox;
	OyMaterialSystem::D3D9MaterialInfo		MaterialModifier;
	

	OyD3D9StaticBuffer();
	~OyD3D9StaticBuffer();
};


/////////////////////////////////////////////////////////////////////////////////////////

class OyD3D9VertexCacheManager : public OyVertexCacheManager
{
public:
	static const int MAX_UPOS_DBUFFERSIZE	= 8192;
	static const int MAX_UTEX_DBUFFERSIZE	= 8192;
	static const int MAX_UCOLOR_DBUFFERSIZE = 8192;
	static const int MAX_UPOSNORMALCOLORTEX_DBUFFERSIZE = 8192;

	static const int INIT_UPOS_VertexCache_NUM	= 2;
	static const int INIT_UTEX_VertexCache_NUM	= 2;
	static const int INIT_UCOLOR_VertexCache_NUM= 2;
	static const int INIT_UPOSNORMALCOLORTEX_VertexCache_NUM= 2;

	static const int INIT_SYNC_SB_RESOURCE = 1024;

    OyD3D9VertexCacheManager(	OySkinManager *pSkinManager,
								LPDIRECT3DDEVICE9 pDevice,
								OyDirect3D9 *pOyD3D9 );
    virtual ~OyD3D9VertexCacheManager(void);

	virtual HRESULT		CreateStaticBuffer(	OY_VERTEXTYPE VertexType,
											UINT  nSkinID,
											UINT  nVertexNum, 
											UINT  nIndexNum, 
											const void *pVerts,
											const WORD *pIndis,
											UINT *pnID );
	virtual HRESULT		DeferedCreateStaticBuffer(
											OY_VERTEXTYPE VertexType,
											UINT  nSkinID,
											UINT  nVertexNum, 
											UINT  nIndexNum, 
											const void *pVerts,
											const WORD *pIndis );

	virtual HRESULT		RenderStaticBuffer( UINT nSBufferID );
	virtual HRESULT		RenderStaticBuffer( UINT nSBufferID, UINT SkinID );
	virtual HRESULT		RenderAllStaticBuffer();

	virtual void		DeferedClearAllStaticBuffer();
	virtual HRESULT		DeferedClearStaticBuffer( UINT nSBufferID );
	virtual void		DeferedSyncResource();


	virtual HRESULT		RenderDynamicBuffer(OY_VERTEXTYPE VertexType,
											UINT nSkinID,
											UINT nVertexNum, 
											UINT nIndexNum, 
											const void *pVerts,
											const WORD *pIndis );

	virtual HRESULT		ForcedCommitAll(void);
	virtual HRESULT		ForcedClearAll(void);

    virtual HRESULT		RenderPoints(	OY_VERTEXTYPE	VertexType,
										UINT            nVertexNum,
										const void		*pVerts,
										const OyColor	*pColor );

    virtual HRESULT		RenderLines(	OY_VERTEXTYPE   VertexType,
										UINT            nVertexNum,
										const void		*pVerts,
										const OyColor	*pColor,
										bool            bStrip );

    virtual HRESULT		RenderLine(		const float *fStart,
										const float *fEnd, 
										const OyColor *pColor );

	virtual HRESULT		RenderTriangles(	OY_VERTEXTYPE	VertexType,
											UINT            nVertexNum,
											UINT			nIndexNum,
											const void		*pVerts,
											const WORD		*pIndis,
											const UINT		MaterialID,
											const UINT		ModifierID,
											char*			CustomMaterialStr,
											const UINT		SkinID );

	virtual void		OnDeviceLost(void);
	virtual void		OnDeviceReset(void);

public:
	inline LPDIRECT3DDEVICE9	GetDevice() { return m_pDevice; }

private:
    OySkinManager						*m_pSkinManager;
    LPDIRECT3DDEVICE9					m_pDevice;
    OyDirect3D9							*m_pOyD3D9;
    DoubleLinkedList<OyD3D9StaticBuffer*>	m_pSB;

	
	OyArrayStack<OyD3D9VertexCache*>	m_UPOSCache;				// untransformed position only
	OyArrayStack<OyD3D9VertexCache*>	m_UTEXCache;				// untransformed and no color vertex
	OyArrayStack<OyD3D9VertexCache*>	m_UCOLORCache;				// untransformed and with color vertex
	OyArrayStack<OyD3D9VertexCache*>	m_UPOSNORMALCOLORTEXCache;	// untransformed pos+normal+color+tex
	//OyArrayStack<OyD3D9VertexCache*>	m_ANIMCache;
	//OyArrayStack<OyD3D9VertexCache*>	m_THREETEXCache;
	//OyArrayStack<OyD3D9VertexCache*>	m_UTANCache;

	UINT								m_VertexCacheMaxID;

private:

	// Defered Sync Resource
	struct DLCreateSB
	{
		OY_VERTEXTYPE VertexType;
		UINT  nSkinID;
		UINT  nVertexNum; 
		UINT  nIndexNum;
		const void *pVerts;
		const WORD *pIndis;
	};
	DoubleLinkedList< RingFIFO<DLCreateSB>* > m_SyncCreateSBList[2];
	unsigned short CreateSBListWorkingID;

	struct DLDeleteSB
	{
		UINT SBID;
	};
	DoubleLinkedList< RingFIFO<DLDeleteSB>* > m_SyncDeleteSBList;

};

/////////////////////////////////////////////////////////////////////////////////////////
/**
 * Class for batching together polygons to be rendered in dynamic buffers.
 * Will flush content if requested or if max number of verts/indis in
 * cache is reached.
 */
class OyD3D9VertexCache
{
public:
	OyD3D9VertexCache(	UINT nVertsMax, UINT nIndisMax, 
						UINT nStride, 
						OyD3D9VertexCacheManager *pVCManager,
						OySkinManager *pSkinManager,
						DWORD dwID, LPDIRECT3DVERTEXDECLARATION9 pDecl );
	~OyD3D9VertexCache(void);

	HRESULT Commit();

    HRESULT Add(UINT nVertexNum, UINT nIndexNum, const void *pVerts, const WORD *pIndis);

	inline bool	IsCapacityEnough(UINT nVertexNum, UINT nIndexNum)
	{ 
		return (m_nNumVerts+nVertexNum <= m_nNumVertsMax) &&
			 (m_nNumIndis+nIndexNum <= m_nNumIndisMax);
	}


    void SetSkin(UINT SkinID);
	UINT GetSkinID() { return m_SkinID; }
	void Clear(void);
	void OnDeviceLost(void);
	void OnDeviceReset(void);

    inline bool IsUsedSkinID(UINT SkinID) { return (m_SkinID == SkinID); }
    inline bool IsEmpty(void) { return ((m_nNumVerts > 0) ? false : true); }
    inline int  GetVertexNum(void) { return m_nNumVerts; }	
	inline int  GetIndexNum(void) { return m_nNumIndis; }

public:
    LPDIRECT3DVERTEXBUFFER9				m_pVB;
    LPDIRECT3DINDEXBUFFER9				m_pIB;
    OyD3D9VertexCacheManager			*m_pVCManager;
	OySkinManager						*m_pSkinManager;
    UINT								m_SkinID;
    DWORD								m_dwVertexCacheID;
    LPDIRECT3DVERTEXDECLARATION9		m_pDecl;
	OyAABB								m_BoundingBox;
	OyMaterialSystem::D3D9MaterialInfo	m_MaterialModifier;


    UINT  m_nNumVertsMax;   // maximum verts in buffer
    UINT  m_nNumIndisMax;   // maximum indices in buffer
    UINT  m_nNumVerts;      // actual number in buffer
    UINT  m_nNumIndis;      // actual number in buffer
    UINT  m_nStride;        // stride of one vertex element

	bool  m_bCommited;
};

#endif